package com.jw.qme.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jw.qme.domain.dto.FriendDTO;
import com.jw.qme.domain.dto.UserDTO;
import com.jw.qme.domain.enun.FriendStatus;
import com.jw.qme.domain.po.Friend;
import com.jw.qme.domain.po.User;
import com.jw.qme.mapper.FriendMapper;
import com.jw.qme.mapper.UserMapper;
import com.jw.qme.service.UserService;
import com.jw.qme.socket.SocketService;
import com.jw.qme.socket.message.MessageType;
import com.jw.qme.utils.PasswordUtils;
import com.jw.qme.utils.RSAUtil;
import com.jw.qme.utils.TransactionSynchronizationUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

/**
 * ClassName: com.jw.qme.service.impl
 * Datetime: 2025/4/4 下午7:31
 * Description:
 *
 * @author 汪佳泉
 * @version 1.0
 * @since 1.0
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService, ApplicationContextAware {


    private final UserMapper userMapper;

    private final FriendMapper friendMapper;

    @Value("${socket.key.publicKey}")
    private String publicKey;

    @Value("${socket.key.privateKey}")
    private String privateKey;

    @Autowired
    private SocketService socketService;

    // Spring上下文容器
    private static ApplicationContext applicationContext;

    public UserServiceImpl(UserMapper userMapper, FriendMapper friendMapper) {
        this.userMapper = userMapper;
        this.friendMapper = friendMapper;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public Boolean userRegister(UserDTO userDTO) {
        if(userDTO.getUsername() == null) throw new RuntimeException("用户名不能为空");
        if(userDTO.getPassword() == null) throw new RuntimeException("账户密码不能为空");
        User one = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userDTO.getUsername()));
        if(one != null) throw new RuntimeException("该账户已被注册");
        String encryptedPassword = PasswordUtils.encryptPasswordWithSHA256(userDTO.getPassword());
        boolean save = save(User.builder().online(false).username(userDTO.getUsername()).password(encryptedPassword).build());
        return save;
    }

    @Override
    public String userLogin(UserDTO userDTO) {
        if(userDTO.getUsername() == null) throw new RuntimeException("用户名不能为空");
        if(userDTO.getPassword() == null) throw new RuntimeException("账户密码不能为空");
        User user = getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userDTO.getUsername()));
        if(user == null) throw new RuntimeException("用户不存在");
        String token = "null";
        if(PasswordUtils.encryptPasswordWithSHA256(userDTO.getPassword()).equals(user.getPassword())){
            // 用户登入成功 生成对应的令牌
            StpUtil.login(user.getUsername());
        } else throw new RuntimeException("密码不正确，请核对密码");
        // 将 Token 返回给客户端 由客户端手动进行维护
        return StpUtil.getTokenValue();
    }

    @Override
    public boolean sendSymmetricKey(String symmetricKey) throws Exception {
        // 获取用户信息
        String loginUser = (String)StpUtil.getLoginId();
        // 拿到服务器私钥 解密
        String decrypt = RSAUtil.decryptByPrivateKey(symmetricKey, privateKey);
        // System.out.println(decrypt);
        System.out.println(decrypt);
        // 将对称密钥保存到上下文中
        Map<String,String> socketKeys = applicationContext.getBean("symmetricKeys", Map.class);
        socketKeys.put(loginUser,decrypt);
        System.out.println("保存了   "+ loginUser +"   对称密钥");
        return true;
    }

    @Override
    public String getPublicKey() {
        return publicKey;
    }

    @Override
    public User findUser(String searchkey) {
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getUsername,searchkey);
        return userMapper.selectOne(userLambdaQueryWrapper);
    }

    @Transactional
    @Override
    public Boolean friend(FriendDTO friendDto) {
        FriendStatus friendStatus = FriendStatus.fromValue(friendDto.getStatus());
        String friendName = friendDto.getFriendName();
        String loginId = (String)StpUtil.getLoginId();
        int count = 0;
        switch (friendStatus){
            case ACCEPTED :
                // 已同意
                friendMapper.updateStatusByPrimaryKey(friendName,loginId,FriendStatus.ACCEPTED.getValue());
                // 发送一个通过的消息通知 使用工具类确保数据落盘后 再查询数据库
                TransactionSynchronizationUtils.afterCommit(()->{
                    socketService.sendMessage(loginId,friendName,"好友申请已通过，您与" + loginId + "成为好友啦", MessageType.NOTIFICATION);
                });
                break;
            case PENDING :
                // 待处理 userId 为好友申请发起人
                // 先去查询
                Friend friend = friendMapper.selectFriendRelation(loginId, friendName);
                if(friend != null && friend.getStatus() == FriendStatus.ACCEPTED.getValue()){
                    throw new RuntimeException("你们已经是好友了，请勿重复添加");
                } else if(friend != null && friend.getStatus() == FriendStatus.PENDING.getValue()){
                    throw new RuntimeException("你已经发起过请求了，请耐心等待");
                }
                // 将这条记录删除
                if(friend != null){
                    friendMapper.delete(new LambdaQueryWrapper<Friend>()
                            .eq(Friend::getUserId, friend.getUserId())
                            .eq(Friend::getFriendId,friend.getFriendId())
                            .eq(Friend::getStatus,friend.getStatus()));
                }
                // 插入新的请求
                Friend friendNew = new Friend(loginId,friendName,FriendStatus.PENDING.getValue());
                count = friendMapper.insert(friendNew);
                // 推送一个消息给有好友申请的客户端 客户端接收到这个id后 在全局主动调用一下查询好友申请列表的接口
                TransactionSynchronizationUtils.afterCommit(()->{
                    socketService.sendMessage(loginId,friendName,loginId + "请求添加你为好友", MessageType.FRIEND_REQUEST);
                });
                break;
            case REJECTED :
                // 拒绝
                friendMapper.updateStatusByPrimaryKey(friendName,loginId,FriendStatus.REJECTED.getValue());
                // 发送一个拒绝的消息通知
                TransactionSynchronizationUtils.afterCommit(()->{
                    socketService.sendMessage(loginId,friendName, loginId + "拒绝了您的好友申请",MessageType.NOTIFICATION);
                });
                break;
            case DELETED:
                // 删除
                friendMapper.updateStatusByPrimaryKey(friendName,loginId,FriendStatus.DELETED.getValue());
                break;
            default:
                System.out.println("未知好友操作类型");
        }
        return count > 0;
    }



}
